/**
 *  @file MemPoolLock.c
 */

#if defined(WIN32)
#   include <windows.h>
#elif defined(linux)
#   include <stdlib.h>
#   include <pthread.h>
#endif

#include "../commontypes.h"
#include "InternalLock.h"

#if defined(WIN32)
typedef struct _globallock
{
   CRITICAL_SECTION lock;
} globallock_t;
#elif defined(linux)

typedef struct _globallock
{
   pthread_mutex_t lock;
} globallock_t;

/*
 *  Use this custom attr enum instead of 'PTHREAD_MUTEX_RECURSIVE'
 */
enum {
   ATTR_PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP
};
#endif


PRIVATE globallock_t st_lockTable[NR_LOCKPARTIES];


void INTL_InitAllLocks(void)
{
   int i = 0;
   for (i = 0; i < NR_LOCKPARTIES; ++i) {
#if defined(WIN32)
       InitializeCriticalSection(&(st_lockTable[i].lock));
#elif defined(linux)
	   pthread_mutexattr_t mutexAttr;

	   pthread_mutexattr_init(&mutexAttr);
	   // make it recursive so that acquiring the same mutex more than once on the same thread won't cause deadlock
	   pthread_mutexattr_settype(&mutexAttr, ATTR_PTHREAD_MUTEX_RECURSIVE); 
	   pthread_mutex_init(&(st_lockTable[i].lock), &mutexAttr);
	   pthread_mutexattr_destroy(&mutexAttr);
#endif
   }
}

/**
 *  Called before entering critical section. Can be called more than once on the same thread
 *  without deadlock but need to call the same number of 'INTL_ReleaseLock' below.
 */
void INTL_AcquireLock(lockparty_t party)
{
#if defined(WIN32)
   EnterCriticalSection(&(st_lockTable[party].lock));
#elif defined(linux)
   pthread_mutex_lock(&(st_lockTable[party].lock));
#endif
}

/**
 *  Call to leave critical section. Balance the number of 'INTL_AcquireLock' and 'INTL_ReleaseLock'.
 */
void INTL_ReleaseLock(lockparty_t party)
{
#if defined(WIN32)
   LeaveCriticalSection(&(st_lockTable[party].lock));
#elif defined(linux)
   pthread_mutex_unlock(&(st_lockTable[party].lock));
#endif
}

/**
 *  Delete all internal locks
 */
void INTL_DeleteAllLocks(void)
{
   int i = 0;
   for (i = 0; i < NR_LOCKPARTIES; ++i) {
#if defined(WIN32)
      DeleteCriticalSection(&(st_lockTable[i].lock));
#elif defined(linux)
      pthread_mutex_destroy(&(st_lockTable[i].lock));
#endif
   }
}
